﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using ifunction.LifeVC.CheckInServiceCore;
using ifunction.LifeVC.CheckInServiceCore.Properties;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;


namespace ifunction.LifeVC.CheckInService
{
    /// <summary>
    /// Class LifeVCSession.
    /// </summary>
    [DataContract]
    [KnownType(typeof(LifeVCAccount))]
    public class LifeVCSession : LifeVCAccount
    {
        /// <summary>
        /// The is debug
        /// </summary>
        protected bool isDebug = false;

        /// <summary>
        /// The cookie container
        /// </summary>
        protected CookieContainer cookieContainer = new CookieContainer();

        /// <summary>
        /// Initializes a new instance of the <see cref="LifeVCSession"/> class.
        /// </summary>
        public LifeVCSession()
            : this(null)
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="LifeVCSession"/> class.
        /// </summary>
        /// <param name="account">The account.</param>
        public LifeVCSession(LifeVCAccount account, bool isDebug = false)
            : base()
        {
            this.isDebug = isDebug;
            if (account != null)
            {
                this.Email = account.Email;
                this.CellPhone = account.CellPhone;
            }
        }

        /// <summary>
        /// Logins this instance.
        /// </summary>
        /// <returns><c>true</c> if succeed to login, <c>false</c> otherwise.</returns>
        public bool Login()
        {
            var request = this.CreateLoginRequest();
            WebResponse response = null;

            try
            {
                response = request.GetResponse();
                string content = ReadAsText(response, Encoding.UTF8);
                JToken jObject = JToken.Parse(content);

                if (jObject.SelectToken("Status").Value<int>() == 1)
                {
                    this.HasLogin = true;

                    if (this.isDebug)
                    {
                        Framework.Logger.LogMessageWithTimeStamp(string.Format("{0} has signed in.", this.Email));
                    }

                    return true;
                }
                else
                {
                    this.HasLogin = false;
                    throw new Exception(jObject.SelectToken("Message").Value<string>());
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }
        }

        /// <summary>
        /// Checks the information.
        /// </summary>
        /// <returns><c>true</c> if succeed to check in, <c>false</c> otherwise.</returns>
        public bool CheckIn(out string message)
        {
            var request = this.CreateCheckInRequest();
            WebResponse response = null;
            message = string.Empty;

            Framework.Logger.LogMessageWithTimeStamp(string.Format("{0} is ready to check in.", this.Email));

            try
            {
                response = request.GetResponse();
                string content = ReadAsText(response, Encoding.UTF8);
                JToken jObject = JToken.Parse(content);

                if (jObject.SelectToken("Status").Value<int>() > 0)
                {
                    this.LastCheckInStamp = DateTime.Now;
                    message = jObject.SelectToken("Message").Value<string>();

                    Framework.Logger.LogMessageWithTimeStamp(string.Format("{0} check in completed: {1}", this.Email, message));
                    return true;
                }
            }
            catch { }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }

            return false;
        }

        /// <summary>
        /// Checks the sign information.
        /// </summary>
        /// <returns><c>true</c> if is sign in, <c>false</c> otherwise.</returns>
        public bool CheckSignIn()
        {
            var request = this.CreateCheckSignInRequest();
            WebResponse response = null;
            Framework.Logger.LogMessageWithTimeStamp(string.Format("{0} is ready to keep signing in status", this.Email));

            try
            {
                response = request.GetResponse();
                string content = ReadAsText(response, Encoding.UTF8);
                JToken jObject = JToken.Parse(content);

                var data = jObject.SelectToken("InnerData");

                var isSign = data.SelectToken("signedIn").Value<bool>();
                var points = data.SelectToken("i").Value<int>();

                this.HasLogin = isSign;
                this.Points = points;

                Framework.Logger.LogMessageWithTimeStamp(string.Format("{0} complete checking sign in status: {1}", this.Email, isSign.ToString()));

                return isSign;
            }
            catch (Exception ex)
            {
                Framework.Logger.LogException(ex);
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }

            return false;

        }

        /// <summary>
        /// Creates the login request.
        /// </summary>
        /// <param name="cellPhone">The cell phone.</param>
        /// <param name="email">The email.</param>
        /// <returns>HttpWebRequest.</returns>
        protected HttpWebRequest CreateLoginRequest()
        {
            HttpWebRequest request = this.GenerateHttpRequest("http://account.lifevc.com/Account/login?rt=/UserCenter", "http://account.lifevc.com/Account/login?rt=/UserCenter", true);

            Dictionary<string, string> post = new Dictionary<string, string>();
            post.Add("userName", this.Email);
            post.Add("password", this.CellPhone);
            post.Add("validation", "");

            FillData(request, "POST", post);

            return request;
        }

        /// <summary>
        /// Creates the check information request.
        /// </summary>
        /// <returns>HttpWebRequest.</returns>
        protected HttpWebRequest CreateCheckSignInRequest()
        {
            //string random = ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds).ToString();
            HttpWebRequest request = this.GenerateHttpRequest("http://account.lifevc.com/usercenter/checksignin", "http://account.lifevc.com/usercenter", true);

            Dictionary<string, string> post = new Dictionary<string, string>();
            FillData(request, "POST", post);

            return request;
        }

        /// <summary>
        /// Creates the check information request.
        /// </summary>
        /// <returns>HttpWebRequest.</returns>
        protected HttpWebRequest CreateCheckInRequest()
        {
            //    string random = ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds).ToString();
            HttpWebRequest request = this.GenerateHttpRequest("http://account.lifevc.com/usercenter/doSignIn", "http://account.lifevc.com/UserCenter", true);
            Dictionary<string, string> post = new Dictionary<string, string>();
            FillData(request, "POST", post);

            return request;
        }

        /// <summary>
        /// Generates the HTTP request.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="referer">The referer.</param>
        /// <param name="isAjaxRequest">The is ajax request.</param>
        /// <returns>System.Net.HttpWebRequest.</returns>
        protected HttpWebRequest GenerateHttpRequest(string url, string referer, bool isAjaxRequest = false)
        {
            var request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Referer = referer;
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.2.1.1000 Chrome/30.0.1551.0 Safari/537.36";
            request.Accept = "*/*";
            request.Method = "GET";
            request.CookieContainer = this.cookieContainer;

            if (isAjaxRequest)
            {
                request.Headers.Add("X-Requested-With", "XMLHttpRequest");
            }

            return request;
        }

        /// <summary>
        /// Fills the data.
        /// </summary>
        /// <param name="httpWebRequest">The HTTP web request.</param>
        /// <param name="method">The method.</param>
        /// <param name="dataMappings">The data mappings.</param>
        protected static void FillData(HttpWebRequest httpWebRequest, string method, Dictionary<string, string> dataMappings)
        {
            if (httpWebRequest != null)
            {
                StringBuilder sb = new StringBuilder();
                if (dataMappings != null)
                {
                    foreach (string key in dataMappings.Keys)
                    {
                        string value = string.Empty;
                        if (dataMappings[key] != null)
                        {
                            value = dataMappings[key];
                        }
                        sb.Append(key + "=" + value.Trim() + "&");
                    }

                }
                if (sb.Length > 0)
                {
                    sb.Remove(sb.Length - 1, 1);
                }
                ASCIIEncoding encoding = new ASCIIEncoding();
                byte[] data = encoding.GetBytes(sb.ToString());

                httpWebRequest.Method = method;
                httpWebRequest.ContentType = "application/x-www-form-urlencoded";
                httpWebRequest.ContentLength = data.Length;
                Stream stream = httpWebRequest.GetRequestStream();
                stream.Write(data, 0, data.Length);
                stream.Close();
            }
        }

        /// <summary>
        /// Reads the asynchronous text.
        /// </summary>
        /// <param name="webResponse">The web response.</param>
        /// <param name="encoding">The encoding.</param>
        /// <returns>System.String.</returns>
        /// <exception cref="System.Exception">ReadAsText</exception>
        protected static string ReadAsText(WebResponse webResponse, Encoding encoding = null)
        {
            string result = string.Empty;

            if (webResponse != null)
            {
                try
                {
                    using (Stream responseStream = webResponse.GetResponseStream())
                    {
                        if (encoding == null)
                        {
                            encoding = Encoding.UTF8;
                        }
                        StreamReader streamReader = new StreamReader(responseStream, encoding);
                        result = streamReader.ReadToEnd();
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("ReadAsText", ex);
                }
                finally
                {
                    webResponse.Close();
                }
            }

            return result;
        }
    }
}
